package com.hwtx.form.persistence;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hwtx.form.domain.repo.OrgUserRepo;
import com.hwtx.form.domain.repo.RoleUserRepo;
import com.hwtx.form.domain.repo.SysUserRepo;
import com.hwtx.form.domain.vo.UserRole;
import io.geekidea.boot.auth.service.LoginRedisService;
import io.geekidea.boot.auth.util.LoginUtil;
import io.geekidea.boot.common.constant.CommonConstant;
import io.geekidea.boot.framework.exception.BusinessException;
import io.geekidea.boot.framework.page.OrderByItem;
import io.geekidea.boot.framework.page.OrderMapping;
import io.geekidea.boot.framework.page.Paging;
import io.geekidea.boot.system.dto.*;
import io.geekidea.boot.system.entity.SysUser;
import io.geekidea.boot.system.mapper.SysUserMapper;
import io.geekidea.boot.system.query.SysUserQuery;
import io.geekidea.boot.system.vo.SysUserVo;
import io.geekidea.boot.util.PagingUtil;
import io.geekidea.boot.util.PasswordUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

import static com.hwtx.form.util.JacksonUtil.object2json;

/**
 * 系统用户 服务实现类
 *
 * @since 2022-12-26
 */
@Slf4j
@Service
public class SysUserRepoImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserRepo {

    @Resource
    private RoleUserRepo roleUserRepo;
    @Resource
    private LoginRedisService LoginRedisService;
    @Resource
    private OrgUserRepo orgUserRepo;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long addSysUser(UserDto dto) {
        checkUsernameExists(dto.getUsername());
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(dto, sysUser);
        // 密码加盐
        Pair<String, String> pair = genPwd(sysUser.getPassword());
        sysUser.setSalt(pair.getRight());
        sysUser.setPassword(pair.getLeft());
        save(sysUser);
        return sysUser.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long updateSysUser(UserDto dto) {
        SysUser sysUser = getById(dto.getId());
        if (sysUser == null) {
            throw new BusinessException("系统用户不存在");
        }
        BeanUtils.copyProperties(dto, sysUser);
        sysUser.setUpdateTime(new Date());
        sysUser.setUpdateId(LoginUtil.getUsername());
        updateById(sysUser);
        return sysUser.getId();
    }

    @Override
    public boolean updateSysUsers(BulkUserDto dto) {
        dto.getIds().forEach(id -> {
            SysUser sysUser = getById(id);
            if (sysUser == null) {
                throw new BusinessException("系统用户不存在");
            }
            sysUser.setUpdateTime(new Date());
            BeanUtils.copyProperties(dto, sysUser);
            updateById(sysUser);
        });
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteSysUser(Long id) {
        return removeById(id);
    }

    @Override
    public SysUserVo getSysUserById(Long id) {
        return baseMapper.getSysUserById(id);
    }

    @Override
    public Paging<SysUserVo> getSysUserPage(SysUserQuery query) {
        OrderMapping orderMapping = new OrderMapping();
        orderMapping.put("createTime", "create_time");
        PagingUtil.handlePage(query, orderMapping, OrderByItem.desc("create_time"));
        List<SysUserVo> users = baseMapper.getSysUserPage(query);
        List<Long> userIds = users.stream().map(SysUserVo::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(userIds)) {
            return new Paging<>();
        }
        Set<UserRole> userRoles = new HashSet<>();
        userRoles.addAll(roleUserRepo.getUserRoles(userIds));
        userRoles.addAll(orgUserRepo.getOrgRolesByUserId(userIds));
        Map<Long, List<String>> userRoleMap = userRoles.stream().collect(Collectors.groupingBy(UserRole::getUserId, Collectors.mapping(user -> user.getRoleName() + ":" + user.getRoleId(), Collectors.toList())));
        users.forEach(user -> user.setRoleInfos(userRoleMap.get(user.getId())));
        return new Paging<>(users);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean resetSysUserPassword(SysUserResetPasswordDto sysUserResetPasswordDto) {
        boolean ret = true;
        for (Long userId : sysUserResetPasswordDto.getIds()) {
            log.info("管理员重置用户密码：{}", userId);
            SysUser sysUser = getById(userId);
            if (sysUser == null) {
                throw new BusinessException("系统用户不存在");
            }
            String password = sysUserResetPasswordDto.getPassword();
            ret = ret && handleUpdatePassword(userId, sysUser.getUsername(), password);
        }
        return ret;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateProfile(SysUserUpdateProfileDto sysUserUpdateProfileDto) {
        Long id = LoginUtil.getUserId();
        SysUser sysUser = getById(id);
        if (sysUser == null) {
            throw new BusinessException("用户信息不存在");
        }
        LambdaUpdateWrapper<SysUser> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(SysUser::getNickname, sysUserUpdateProfileDto.getNickname());
        lambdaUpdateWrapper.set(SysUser::getPhone, sysUserUpdateProfileDto.getPhone());
        lambdaUpdateWrapper.set(SysUser::getEmail, sysUserUpdateProfileDto.getEmail());
        lambdaUpdateWrapper.set(SysUser::getHead, sysUserUpdateProfileDto.getHead());
        lambdaUpdateWrapper.eq(SysUser::getId, id);
        return update(lambdaUpdateWrapper);
    }

    @Override
    public void checkUsernameExists(String username) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, username);
        long count = count(wrapper);
        if (count > 0) {
            throw new BusinessException(username + "用户名已经存在");
        }
    }

    @Override
    public boolean importExcel(MultipartFile multipartFile) throws Exception {
        String originalFilename = multipartFile.getOriginalFilename();
        log.info("导入的Excel文件名称：" + originalFilename);
        String extension = Objects.requireNonNull(FilenameUtils.getExtension(originalFilename)).toLowerCase();
        if (!(extension.endsWith(CommonConstant.XLS) || extension.endsWith(CommonConstant.XLSX))) {
            throw new BusinessException("只能导入xls或xlsx格式的Excel文件");
        }
        InputStream inputStream = multipartFile.getInputStream();

        EasyExcel.read(inputStream, SysUserExcelDto.class, new PageReadListener<SysUserExcelDto>(dataList -> {
            for (SysUserExcelDto demoData : dataList) {
                log.info("读取到一条数据{}", object2json(demoData));
            }
        }, 10)).sheet().doRead();


        return false;
    }

    @Override
    public List<Long> getRolesByUserId(Long userId) {
        return baseMapper.getRolesByUserId(userId);
    }

    @Override
    public List<Long> getOrgIdsByUserId(Long userId) {
        return baseMapper.getOrgIdsByUserId(userId);
    }

    @Override
    public Paging<SysUserVo> getAssignedOrgUsersPage(SysUserQuery query) {
        OrderMapping orderMapping = new OrderMapping();
        orderMapping.put("createTime", "create_time");
        PagingUtil.handlePage(query, orderMapping, OrderByItem.desc("create_time"));
        List<SysUserVo> users = baseMapper.getAssignedOrgUsersPage(query);
        return new Paging<>(users);
    }

    /**
     * 修改密码并删除该用户当前的登录信息
     */
    private boolean handleUpdatePassword(Long id, String userName, String password) {
        // 生产新的盐值
        Pair<String, String> pair = genPwd(password);
        String newSalt = pair.getRight();
        String newPassword = pair.getLeft();
        // 修改密码
        LambdaUpdateWrapper<SysUser> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(SysUser::getPassword, newPassword);
        lambdaUpdateWrapper.set(SysUser::getSalt, newSalt);
        lambdaUpdateWrapper.set(SysUser::getUpdateTime, new Date());
        lambdaUpdateWrapper.eq(SysUser::getId, id);
        // 清除当前用户登录信息
        LoginRedisService.deleteLoginInfo(userName);
        return update(lambdaUpdateWrapper);
    }

    @Override
    public Pair<String, String> genPwd(String pwd) {
        String salt = RandomStringUtils.randomNumeric(6);
        String password = PasswordUtil.encrypt(pwd, salt);
        return Pair.of(password, salt);
    }
}
